package com.hundsun.epay.autosimu.config.xml;

import java.util.Properties;

import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.hundsun.epay.autosimu.config.Channel;
import com.hundsun.epay.autosimu.config.Configuration;
import com.hundsun.epay.autosimu.config.ControllerField;
import com.hundsun.epay.autosimu.config.ControllerResp;
import com.hundsun.epay.autosimu.config.NamesConstants;
import com.hundsun.epay.autosimu.config.PayCorporation;
import com.hundsun.epay.autosimu.config.Trade;
import com.hundsun.epay.autosimu.enums.CommunicationMethod;
import com.hundsun.epay.autosimu.enums.ControllerFieldType;
import com.hundsun.epay.autosimu.enums.TradeType;
import com.hundsun.epay.autosimu.exception.XmlParseException;
import com.hundsun.epay.autosimu.utils.StringUtility;

/**
 * xml配置解析
 * @author qujb22570
 *
 */
public class AutoSimuGeneratorConfigurationParser {
	private Properties extraProperties;
	private Properties configProperties;
	public AutoSimuGeneratorConfigurationParser(Properties extraProperties) {
		if(extraProperties == null){
			this.extraProperties = new Properties();
		}else{
			this.extraProperties = extraProperties;
		}
		configProperties = new Properties();
	}
	
	public Configuration parseConfiguration(Element rootNode) throws XmlParseException {
		Configuration configuration = new Configuration();
		NodeList nodeList = rootNode.getChildNodes();
		for(int i = 0; i < nodeList.getLength(); i ++){
			Node node = nodeList.item(i);
			if(node.getNodeType() != Node.ELEMENT_NODE){
				continue;
			}
			if(NamesConstants.NODE_PAY_CORPORATION.equals(node.getNodeName())){
				parsePayCorpation(configuration, node);
			}
		}
		return configuration;
		
	}
	
	protected void parsePayCorpation(Configuration configuration, Node node) throws XmlParseException{
		Properties attributes = parseAttributes(node);
		String id = attributes.getProperty(NamesConstants.ATTRIBUTE_ID);
		String className = attributes.getProperty(NamesConstants.ATTRIBUTE_CLASS_NAME);
		String commMethod = attributes.getProperty(NamesConstants.ATTRIBUTE_COMMUNICATION_METHOD);
		String packageName = attributes.getProperty(NamesConstants.ATTRIBUTE_PACKAGE_NAME);
		
		CommunicationMethod method = commMethod == null ? null : CommunicationMethod.getMethodByCode(commMethod);
		PayCorporation corp = new PayCorporation();
		corp.setId(id);
		corp.setCommMethod(method);
//		corp.setClassName(className);
		corp.setPackageName(packageName);
		configuration.addCorp(corp);
		NodeList nodeList = node.getChildNodes();
		for(int i = 0; i < nodeList.getLength(); i ++){
			Node childNode = nodeList.item(i);
			if(childNode.getNodeType() != Node.ELEMENT_NODE){
				continue;
			}
			if(NamesConstants.NODE_PAY_CHANNEL.equals(childNode.getNodeName())){
				parseChannel(corp, childNode);
			}
		}
	}
	
	protected void parseChannel(PayCorporation corporation, Node node) throws XmlParseException{
		Properties attributes = parseAttributes(node);
		String id = attributes.getProperty(NamesConstants.ATTRIBUTE_ID);
		String commMethod = attributes.getProperty(NamesConstants.ATTRIBUTE_COMMUNICATION_METHOD);
		CommunicationMethod method = commMethod == null ? null : CommunicationMethod.getMethodByCode(commMethod);
		Channel channel = new Channel();
		channel.setId(id);
		channel.setCommMethod(method);
		channel.setClassName(attributes.getProperty(NamesConstants.ATTRIBUTE_CLASS_NAME));
		corporation.addChanel(channel);
		
		NodeList nodeList = node.getChildNodes();
		for(int i = 0; i < nodeList.getLength(); i ++){
			Node childNode = nodeList.item(i);
			if(childNode.getNodeType() != Node.ELEMENT_NODE){
				continue;
			}
			if(NamesConstants.NODE_PAY_TRADE.equals(childNode.getNodeName())){
				parseTrade(channel, childNode);
			}
		}
	}
	
	protected void parseTrade(Channel channel, Node node) throws XmlParseException{
		Properties attributes = parseAttributes(node);
		String id = attributes.getProperty(NamesConstants.ATTRIBUTE_ID);
		String type = attributes.getProperty(NamesConstants.ATTRIBUTE_TYPE);
		String commMethod = attributes.getProperty(NamesConstants.ATTRIBUTE_COMMUNICATION_METHOD);
		CommunicationMethod method = commMethod == null ? null : CommunicationMethod.getMethodByCode(commMethod);
		TradeType tradeType = type == null ? null : TradeType.getTypeByCode(type);
		Trade trade = new Trade();
		trade.setId(id);
		trade.setCommMethod(method);
		trade.setType(tradeType);
		trade.setMethodName(attributes.getProperty(NamesConstants.ATTRIBUTE_METHON_NAME));
		trade.setNotifyName(attributes.getProperty(NamesConstants.ATTRIBUTE_NOTIFY_NAME));
		trade.setNotify(attributes.getProperty(NamesConstants.ATTRIBUTE_NOTIFY));
		trade.setSync(StringUtility.parseBoolean(attributes.getProperty(NamesConstants.ATTRIBUTE_SYNC)));
		channel.addTrade(trade);
		
		NodeList nodeList =  node.getChildNodes();
		for(int i = 0; i < nodeList.getLength(); i ++){
			Node childNode = nodeList.item(i);
			if(childNode.getNodeType() != Node.ELEMENT_NODE){
				continue;
			}
			if(NamesConstants.NODE_CONTROLLER_CFIELDS.equals(childNode.getNodeName())){
				parseCFields(trade, childNode);
			}
			if(NamesConstants.NODE_CONTROLLER_CRESPS.equals(childNode.getNodeName())){
				parseCResps(trade, childNode);
			}
		}
	}
	
	protected void parseCFields(Trade trade, Node node){
		NodeList nodeList = node.getChildNodes();
		for(int i = 0; i < nodeList.getLength(); i ++){
			Node childNode = nodeList.item(i);
			if(childNode.getNodeType() != Node.ELEMENT_NODE){
				continue;
			}
			if(NamesConstants.NODE_CONTROLLER_CFIELD.equals(childNode.getNodeName())){
				parseCField(trade, childNode);
			}
		}
	}
	
	protected void parseCField(Trade trade, Node node){
		Properties attributes = parseAttributes(node);
		String id = attributes.getProperty(NamesConstants.ATTRIBUTE_ID);
		String type = attributes.getProperty(NamesConstants.ATTRIBUTE_TYPE);
		String key = attributes.getProperty(NamesConstants.ATTRIBUTE_KEY);
		String rule = attributes.getProperty(NamesConstants.ATTRIBUTE_RULE);
		String control = attributes.getProperty(NamesConstants.ATTRIBUTE_CONTROL);
		String ref = attributes.getProperty(NamesConstants.ATTRIBUTE_REF);
		String separator = attributes.getProperty(NamesConstants.ATTRIBUTE_SEPARATOR);
		
		ControllerFieldType ctype = ControllerFieldType.getTypeByCode(type);
		System.out.println("Parse: key=" + key + " type=" + ctype);
		ControllerField field = new ControllerField();
		field.setId(id);
		field.setType(ctype);
		field.setKey(key);
		field.setRule(rule);
		field.setControl(Boolean.valueOf(control));
		field.setRefField(ref);
		field.setSeparator(separator);
		trade.addCField(id, field);
	}
	
	protected void parseCResps(Trade trade, Node node) throws XmlParseException{
		NodeList nodeList = node.getChildNodes();
		for(int i = 0; i < nodeList.getLength(); i ++){
			Node childNode = nodeList.item(i);
			if(childNode.getNodeType() != Node.ELEMENT_NODE){
				continue;
			}
			if(NamesConstants.NODE_CONTROLLER_CRESP.equals(childNode.getNodeName())){
				parseCResp(trade, childNode);
			}
		}
	}
	
	protected void parseCResp(Trade trade, Node node) throws XmlParseException{
		Properties attributes = parseAttributes(node);
		String rule = attributes.getProperty(NamesConstants.ATTRIBUTE_RULE);
		String template = attributes.getProperty(NamesConstants.ATTRIBUTE_TEMPLATE);
		String importUrl = attributes.getProperty(NamesConstants.ATTRIBUTE_IMPORT);
		ControllerResp cresp = new ControllerResp();
		cresp.setRule(rule);
		cresp.setTemplate(template);
		cresp.setImportUrl(importUrl);
		if(StringUtility.stringHasValue(rule)){
			trade.addCResp(cresp);
		}else if(trade.getDefaultCResp() == null){
			trade.setDefaultCResp(cresp);
		}else{
			throw new XmlParseException("Only one default resp controller");
		}
	}
	
	protected Properties parseAttributes(Node node){
		Properties properties = new Properties();
		NamedNodeMap nnm = node.getAttributes();
		for(int i = 0; i < nnm.getLength(); i ++){
			Node attribute = nnm.item(i);
			properties.put(attribute.getNodeName(), attribute.getNodeValue());
		}
		return properties;
	}
}
